package utils;

import cn.leancloud.LCObject;
import cn.leancloud.LCQuery;
import cn.leancloud.LCUser;
import com.alibaba.fastjson2.JSONObject;
import data.ActionModel;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

import java.util.ArrayList;
import java.util.List;

import static utils.GlobalVar.getActionList;
import static utils.GlobalVar.getActionListSize;

public class DBUtils {
    String className;
    private ActionModel actionModel;
    private LCObject lcObject;
    // 动作索引的增幅
    static long ACTION_INDEX_BASEN_UMBER = 1000000;


    public DBUtils(String className, LCObject lcObject) {
        this.className = className;
        this.lcObject = lcObject;
    }

    public DBUtils(String className) {
        this.className = className;
    }

    public DBUtils() {
    }

    public static LCObject save(String className, Object... fields) {
        LCObject lcObject = newData(className);
        for (int i = 0; i < fields.length; i += 2) {
            lcObject.put((String) fields[i], fields[i + 1]);
        }
        lcObject.save();
        return lcObject;
    }

    public static LCObject newData(String className) {
        LCObject newLcobject = new LCObject(className);
        LCUser lcUser = LCUser.getCurrentUser();
        newLcobject.put(Constant.DB.AUTHOR, lcUser);
        return newLcobject;
    }

    /*
     * @Author Dongle
     * @Description
     * @Date 8:24 2023/1/15
     * @param position 在 listView 中的位置
     * @return
     **/
    public static long getActionIndex(int position) {
        List<ActionModel> actions = getActionList();
        // 如果 listView 为空，说明第一次插入，返回基础值
        if (getActionListSize() == 0) {
            return ACTION_INDEX_BASEN_UMBER;
        }
        // 如果向队尾插入，索引值增加一个量级
        if (getActionListSize() == position) {
            return actions.get(position - 1).getLcObject().getInt(Constant.DB.INDEX) + ACTION_INDEX_BASEN_UMBER;
        }
        // 要插入位置的当前索引
        long currentActionIndex = actions.get(position).getLcObject().getInt(Constant.DB.INDEX);
        // 如果向第一位插入，索引值取半
        if (position == 0) {
            // 第一个位置的值过于小，重排
            if (currentActionIndex < 1) {
                reRangeActionIndex();
                currentActionIndex = actions.get(position).getLcObject().getInt(Constant.DB.INDEX);
            }
            return currentActionIndex / 2;
        } else {
            // 如果向中间插入，取前后索引值 / 2
            long preIndex = actions.get(position - 1).getLcObject().getInt(Constant.DB.INDEX);
            // 前后值过于接近，进行重排
            if (currentActionIndex - preIndex < 1) {
                reRangeActionIndex();
                currentActionIndex = actions.get(position).getLcObject().getInt(Constant.DB.INDEX);
                // 重新获取值
                preIndex = actions.get(position - 1).getLcObject().getInt(Constant.DB.INDEX);
            }
            return (preIndex + currentActionIndex) / 2;
        }

    }

    // 对 actions 的索引值进行重排
    private static void reRangeActionIndex() {
        List<ActionModel> actions = getActionList();
        // 索引值已经用完，需要重排
        long tmpindex = ACTION_INDEX_BASEN_UMBER;
        for (ActionModel action : actions) {
            action.getLcObject().put(Constant.DB.INDEX, tmpindex);
            action.getLcObject().save();
            tmpindex += ACTION_INDEX_BASEN_UMBER;
        }
    }

    /*
     * @Author Dongle
     * @Description 添加一行
     * @Date 22:17 2023/1/4
     * @Param
     * @param className
     * @param data
     * @return
     **/
    public void addRow(JSONObject data, int listViewIndex) {
        LCObject lc = new LCObject(className);
        LCUser author = LCUser.getCurrentUser();
        data.keySet().forEach(key -> lc.put(key, data.get(key)));
        // 插入索引位置
        long actionIndex = getActionIndex(listViewIndex);
        getActionList().add(listViewIndex, new ActionModel(lc));
        lc.put(Constant.DB.INDEX, actionIndex);
        lc.put(Constant.DB.AUTHOR, author);
        if (GlobalVar.getActionList().get(listViewIndex).getBorderPane() != null) {
            GlobalVar.getActionList().get(listViewIndex).getBorderPane().getCenter().requestFocus();
        }
        try {
            lc.save();
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
        }
    }



    public void addRow(int listViewIndex) {
        addRow(JSONObject.of(Constant.DB.DATA, JSONObject.of(Constant.DB.TYPE, Constant.TYPE.TEXT)), listViewIndex);
    }

    public void delete(ActionModel actionModel) {
        this.actionModel = actionModel;
        int currentIndex = getActionList().indexOf(actionModel);
        try {
            actionModel.getLcObject().delete();
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
        }
        deleteLCObjectFromListView();
        // 删除最后一个，选中上一个项目
        if (GlobalVar.getActionList().size() <= currentIndex) {
            GlobalVar.getActionList().get(currentIndex - 1).getBorderPane().getCenter().requestFocus();
        } else {
            // 删除时，选中下一个项目
            GlobalVar.getActionList().get(currentIndex).getBorderPane().getCenter().requestFocus();
        }
    }


    public static LCObject get(String className, String... fields) {
        LCQuery<LCObject> query = new LCQuery<>(className);
        LCUser author = LCUser.getCurrentUser();
        query.whereEqualTo(Constant.DB.AUTHOR, author);
        for (int i = 0; i < fields.length; i += 2) {
            query.whereEqualTo(fields[i], fields[i + 1]);
        }
        LCObject res;
        try {
            res = query.getFirst();
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
            res = null;
        }
        return res;
    }

    public static List<LCObject> getAll(String className) {
        LCQuery<LCObject> query = new LCQuery<>(className);
        LCUser author = LCUser.getCurrentUser();
        query.whereEqualTo(Constant.DB.AUTHOR, author);
        List<LCObject> res;
        try {
            res = query.find();
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
            res = new ArrayList<>();
        }
        return res;
    }

    /*
     * @Author Dongle
     * @Description 保存数据到指定 LCObject 的 Data 字段
     * @Date 22:18 2023/1/4
     * @Param
     * @param key
     * @param value
     * @return
     **/
    public void saveInData(String key, String value) {
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(lcObject.get(Constant.DB.DATA)));
        jsonObject.put(key, value);
        lcObject.put(Constant.DB.DATA, jsonObject);
        GlobalVar.getMainPage().notifyListView(lcObject);
        try {
            lcObject.save();
        } catch (RuntimeException e) {
            System.out.println(e.getMessage());
        }
    }

    public void putInData(String key, String value, LCObject lcObject) {
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(lcObject.get(Constant.DB.DATA)));
        jsonObject.put(key, value);
        lcObject.put(Constant.DB.DATA, jsonObject);
    }

    public void put(String key, Object value, LCObject lcObject) {
        this.lcObject = lcObject;
        put(key, value);
    }

    public void put(String key, Object value) {
        lcObject.put(key, value);
    }


    private void deleteLCObjectFromListView() {
        List<ActionModel> actionList = getActionList();
        actionList.remove(actionModel);
        // 如果删除完了，新增一行
        if (getActionListSize() == 0) {
            addRow(0);
        }
    }

    /*
     * @Author Dongle
     * @Description 方便处理数据结构为 JSON 的字段
     * @Date 18:14 2022/12/31
     * @param key JSON 的 key
     * @param defaultValue 默认值
     * @return JSON value 或默认值
     **/
    public Object getDataOrDefault(String key, String defaultValue) {
        JSONObject res = JSONObject.parseObject(JSONObject.toJSONString(lcObject.get(Constant.DB.DATA)));
        return res.getOrDefault(key, defaultValue);
    }

    public String getDataString(String key, ActionModel actionModel) {
        lcObject = actionModel.getLcObject();
        return getDataString(key);
    }

    public String getDataString(String key) {
        JSONObject res = JSONObject.parseObject(JSONObject.toJSONString(lcObject.get(Constant.DB.DATA)));
        return res.getString(key);
    }


    public boolean loginWithPassword(String username, String password) {
        final boolean[] res = new boolean[1];
        LCUser.logIn(username, password).subscribe(new Observer<LCUser>() {
            public void onSubscribe(Disposable disposable) {
            }

            public void onNext(LCUser user) {
                // 登陆成功
                System.out.println("登陆成功");
                res[0] = true;
            }

            public void onError(Throwable throwable) {
                // 登录失败（可能是密码错误）
                System.out.println("登陆失败");
                res[0] = false;
            }

            public void onComplete() {
            }
        });
        return res[0];

    }

    public boolean loginWithSession() {
        String session = ControllerUtils.getSession();
        if (session == null) {
            return false;
        }
        final boolean[] result = new boolean[1];
        LCUser.becomeWithSessionTokenInBackground(session).subscribe(new Observer<LCUser>() {
            public void onSubscribe(Disposable disposable) {
            }

            public void onNext(LCUser user) {
                // 修改 currentUser
                LCUser.changeCurrentUser(user, true);
                result[0] = true;
            }

            public void onError(Throwable throwable) {
                // session token 无效
                result[0] = false;
            }

            public void onComplete() {
            }
        });
        return result[0];
    }
}